package org.example.wx.client.loadBalance;

import org.example.wx.client.connection.ServiceInfo;

import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class PollingLoadBalancer implements LoadBalancer {

    private static final String metaIndexName = "LBIndex";

    private static final String choosenName = "choosen";

    @Override
    public ServiceInfo choose(List<ServiceInfo> serviceInfos) {
        //如果serviceInfos为空，则说明要调用的service没有启动，并将服务注册到zookeeper当中
        if (serviceInfos == null || serviceInfos.size() == 0) return null;
        List<ServiceInfo> sortedServiceInfos = sort(serviceInfos);
        ServiceInfo choosen = sortedServiceInfos.stream().filter(serviceInfo -> (Boolean) serviceInfo.getLoadBalanceMetaData().get("choosen")).findFirst().orElse(null);
        if (choosen == null) {
            sortedServiceInfos.get(0).getLoadBalanceMetaData().put(metaIndexName, true);
            return sortedServiceInfos.get(0);
        } else {
            int index = sortedServiceInfos.indexOf(choosen);
            return sortedServiceInfos.get((index + 1) % sortedServiceInfos.size());
        }
    }

    @Override
    public void writeMetaData(ServiceInfo serviceInfo, Double LBIndex) {
        Map<String, Object> metaData = new HashMap<>();
        metaData.put(metaIndexName, LBIndex);
        metaData.put(choosenName, false);
        serviceInfo.setLoadBalanceMetaData(metaData);
    }

    public List<ServiceInfo> sort(List<ServiceInfo> serviceInfos) {
        if (serviceInfos == null || serviceInfos.size() == 0) return serviceInfos;
        List<ServiceInfo> sortedServiceInfos = serviceInfos.stream().filter(serviceInfo -> serviceInfo.getLoadBalanceMetaData().get(metaIndexName) != null).collect(Collectors.toList());
        double maxIndex = sortedServiceInfos.stream().map(info -> (Double) info.getLoadBalanceMetaData().get(metaIndexName)).max(Double::compareTo).orElse(Double.valueOf("0"));
        List<ServiceInfo> unsortedServiceInfos = serviceInfos.stream().filter(serviceInfo -> serviceInfo.getLoadBalanceMetaData().get(metaIndexName) == null).collect(Collectors.toList());
        for (int i = 0; i < unsortedServiceInfos.size(); i++) {
            unsortedServiceInfos.get(i).getLoadBalanceMetaData().put(metaIndexName, maxIndex + i + 1);
        }

        serviceInfos.sort(Comparator.comparingDouble(info -> (Double) info.getLoadBalanceMetaData().get(metaIndexName)));

        for (int i = 0; i < serviceInfos.size(); i++) {
            Double index = Integer.valueOf(i + 1).doubleValue();
            serviceInfos.get(i).getLoadBalanceMetaData().put(metaIndexName, index);
        }
        return serviceInfos;
    }
}
